package com.jackrain.nea.ad.utility;

import com.google.common.collect.*;
import com.jackrain.nea.ad.entity.MenuEntity;
import com.jackrain.nea.config.Resources;
import com.jackrain.nea.core.redis.CusRedisTemplate;
import com.jackrain.nea.core.schema.Table;
import com.jackrain.nea.core.schema.TableManager;
import com.jackrain.nea.core.webaction.WebAction;
import com.jackrain.nea.ext.permission.*;
import com.jackrain.nea.util.RedisOpsUtil;
import com.jackrain.nea.utility.ExceptionUtil;
import com.jackrain.nea.web.query.QuerySession;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.SortedMap;

/**
 * @author lzm
 * @date 2017-11-22
 */
@Slf4j
public class MenuManager {
    public static void updateAll(QuerySession session, List<MenuEntity> allMenus, List<HashMap<String, Long>> allMenuActions) {
        TableManager tm = session.getTableManager();
        //更新正式版本的菜单树
        log.debug("doUpdateMenuTree.start正式数据");
        Collection<MenuEntity> allMenusExceptInDev = Collections2.filter(allMenus, entity-> entity.getIsdev() == null || !entity.getIsdev());
        MenuCollection newValue = doUpdateMenuTree(session,tm, allMenusExceptInDev, allMenuActions);
        doUpdateMenuAction(session, newValue, allMenuActions);
        doUpdateRedis(newValue, false);
        log.debug("doUpdateMenuTree.end正式数据");
        //更新下开发模式的菜单树
        log.debug("doUpdateMenuTree.start开发数据");
        newValue = doUpdateMenuTree(session,tm, allMenus, allMenuActions);
        doUpdateMenuAction(session, newValue, allMenuActions);
        doUpdateRedis(newValue, true);
        log.debug("doUpdateMenuTree.end开发数据");
    }

    private static void doUpdateRedis(MenuCollection newValue, boolean isDev) {
        String key = isDev? Permissions.MENU_TREE_IN_DEV_REDIS_KEY: Permissions.MENU_TREE_REDIS_KEY;
        CusRedisTemplate<String, MenuCollection> redisTemplate = RedisOpsUtil.getObjRedisTemplate();
        redisTemplate.opsForValue().set(key, newValue);
        if(isDev){
            Permissions.setMenuTreeInDevMode(newValue);
        }else{
            Permissions.setMenuTree(newValue);
        }
    }

    private static MenuCollection doUpdateMenuTree(QuerySession session, TableManager tm, Collection<MenuEntity> allMenus, List<HashMap<String, Long>> allMenuActions) {
        MenuCollection newValue = new MenuCollection();
        //要求进来的coll必须是排好序的(只有Table/Action两种节点，需要自行补上subSystem和Action节点)
        if (allMenus == null) {
            return newValue;
        }

        for (HashMap<String, Long> actionHash : allMenuActions) {
            Long tableId = actionHash.get("AD_TABLE_ID");
            Long id = actionHash.get("ID");
            if(id == null || id <= 0){
                continue;
            }
            WebAction action = tm.getWebAction(id.intValue());
            if (action != null && action.getDisplayType() == WebAction.DisplayTypeEnum.Accord
                    && tableId != null && tableId > 0) {
                log.warn(String.format("doUpdateMenuTree.actionId:%s是个aliasAction, 对应tableId:%s！", id, tableId));
                //aliasActions.put(tableId, id);
                newValue.addAliasAction(tableId, id);
            }
        }

        MenuNode currentSubSystemNode = null;
        MenuNode currentTableCategoryNode = null;
        MenuNode node = null;
        for (MenuEntity entity : allMenus) {
            try {
                node = new MenuNode();
                MenuType menuType = MenuType.valueOf(entity.getType());
                node.setType(menuType);
                node.setId(entity.getId());
                node.setAd_subsystem_id(entity.getAd_subsystem_id());
                node.setAd_tablecategory_id(entity.getAd_tablecategory_id());
                node.setAd_table_id(entity.getAd_table_id());
                node.setAd_action_id(entity.getAd_action_id());
                node.setOrderno(entity.getOrderno());
                node.setIsdev(entity.getIsdev() == null ? false: entity.getIsdev());
                Long subSystemId = node.getAd_subsystem_id();
                if (subSystemId == null || subSystemId <= 0) {
                    log.warn(String.format("doUpdateMenuTree.菜单项-%s没有配置子系统！", node.getId()));
                    continue;
                }
                Long tableCategoryId = node.getAd_tablecategory_id();
                if (tableCategoryId == null || tableCategoryId <= 0) {
                    log.warn(String.format("doUpdateMenuTree.菜单项-%s没有配置表类别！", node.getId()));
                    continue;
                }

                if (currentSubSystemNode == null || !currentSubSystemNode.getId().equals(node.getAd_subsystem_id())) {
                    currentSubSystemNode = MenuNode.createSubSystemNode(session, node.getAd_subsystem_id());
                    newValue.add(newValue.getRootNode(), currentSubSystemNode);
                    currentTableCategoryNode = null;
                }
                if (currentTableCategoryNode == null || !currentTableCategoryNode.getId().equals(node.getAd_tablecategory_id())) {
                    currentTableCategoryNode = MenuNode.createTableCategoryNode(session, currentSubSystemNode.getId(), node.getAd_tablecategory_id());
                    newValue.add(currentSubSystemNode, currentTableCategoryNode);
                }
                node.setNodeType(MenuNodeType.MENU);
                switch (menuType) {
                    case TABLE:
                        Long tableId = node.getAd_table_id();
                        Table table = null;
                        if (tableId != null && tableId > 0) {
                            table = session.getTableManager().getTable(tableId.intValue());
                        }
                        if (table == null) {
                            log.warn(String.format("doUpdateMenuTree.菜单项-%s没有找到对应的表！", node.getId()));
                            continue;
                        }
                        node.setName(table.getName());
                        node.setDescription(table.getDescription());
                        node.setMask(TableMaskHelper.generateMaskString(table));
                        newValue.add(currentTableCategoryNode, node);
                        break;
                    case ACTION:
                        Long actionId = node.getAd_action_id();
                        WebAction action = null;
                        if (actionId != null && actionId > 0) {
                            action = session.getTableManager().getWebAction(actionId.intValue());
                        }
                        if (action == null) {
                            log.warn(String.format("doUpdateMenuTree.菜单项-%s没有找到对应的动作定义！", node.getId()));
                            continue;
                        }
                        node.setMask(TableMaskHelper.generateActionMask(tm, newValue, actionId));
                        //node.setMask(TableMaskHelper.ONLY_VIEW_MASK);
                        node.setName(action.getName());
                        node.setDescription(action.getDescription());
                        newValue.add(currentTableCategoryNode, node);
                        break;
                    default:
                }
            } catch (Exception e) {
                String message = ExceptionUtil.getMessage(e);
                if(node != null){
                    log.error(String.format("doUpdateMenuTree:%s, node:%s-%s-%s-%s", message, node.getId(), node.getType().getDesc()
                            , node.getAd_subsystem_id(), node.getAd_tablecategory_id()));
                }else{
                    log.error(String.format("doUpdateMenuTree:%s", message));
                }
            }
        }

        return newValue;
    }

    private static void doUpdateMenuAction(QuerySession session, MenuCollection tree, List<HashMap<String, Long>> allMenuActions) {
        TableManager tm = session.getTableManager();

        //先取菜单项下的动作定义
        SortedMap<Long, String> actionMap = Maps.newTreeMap();
        for (HashMap<String, Long> actionHash : allMenuActions) {
            try {
                Long actionId = actionHash.get("ID");
                if(actionId != null){
                    actionMap.put(actionId, "UNKNOWN");
                }
                Long parentActionId = actionHash.get("AD_ACTION_ID");
                Long parentTableId = actionHash.get("AD_TABLE_ID");
                if (tree.fetchByTmId(MenuType.ACTION, actionId) != null) {
                    actionMap.put(actionId, "menu");
                    continue;   //已被定义为菜单项了
                }
                WebAction action = tm.getWebAction(actionId.intValue());
                if (action == null) {
                    String format = Resources.getMessage("doUpdateMenuAction.actionId=%s未找到对应的action", session.getLocale());
                    log.warn(String.format(format, actionId));
                    continue;
                }
                MenuNode node;
                if (action.getDisplayType() != WebAction.DisplayTypeEnum.Accord
                        && (parentActionId == null || parentActionId <= 0)) {
                    node = tree.fetchByTmId(MenuType.TABLE, parentTableId);
                } else {
                    node = tree.fetchByTmId(MenuType.ACTION, parentActionId);
                }

                if (node != null) {
                    if(tree.addActionUnderMenu(node.getId(), actionId)){
                        actionMap.put(actionId, "actionUnderMenu");
                    }
                }
                //往aliasAction下加
                if (parentTableId != null && parentTableId > 0) {
                    Collection<Long> aliasParentActions = tree.fetchAliasActionsByTable(parentTableId);
                    for (Long parentId: aliasParentActions){
                        if(parentId == null || parentId <=0){
                            continue;
                        }
                        node = tree.fetchByTmId(MenuType.ACTION, parentId);
                        if(node != null){
                            if(tree.addActionUnderMenu(node.getId(), actionId)){
                                actionMap.put(actionId, "actionUnderMenu");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                String message = ExceptionUtil.getMessage(e);
                log.error(String.format("doUpdateMenuAction:%s", message));
            }
        }

        //然后取动作定义下的动作定义
        for (HashMap<String, Long> actionHash : allMenuActions) {
            try {
                Long actionId = actionHash.get("ID");
                if (tree.fetchByTmId(MenuType.ACTION, actionId) != null) {
                    continue;   //已被定义为菜单项了
                }
                WebAction action = tm.getWebAction(actionId.intValue());
                if (action == null) {
                    String format = Resources.getMessage("doUpdateMenuAction.actionId=%s未找到对应的action", session.getLocale());
                    log.warn(String.format(format, actionId));
                    continue;
                }

                Long parentActionId = actionHash.get("AD_ACTION_ID");
                Long parentTableId = actionHash.get("AD_TABLE_ID");
                if (tree.containsAction(parentActionId)) {
                    if(tree.addActionUnderAction(parentActionId, actionId)){
                        actionMap.put(actionId, "actionUnderAction");
                    }
                }

                //往aliasAction下加
                if (parentTableId != null && parentTableId > 0) {
                    Collection<Long> aliasParentActions = tree.fetchAliasActionsByTable(parentTableId);
                    for (Long parentId: aliasParentActions){
                        if(parentId == null || parentId <=0){
                            continue;
                        }
                        if (tree.containsAction(parentId)) {
                            if(tree.addActionUnderAction(parentId, actionId)){
                                actionMap.put(actionId, "actionUnderAction");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                String message = ExceptionUtil.getMessage(e);
                log.error(String.format("doUpdateMenuAction:%s", message));
            }
        }

        log.debug(String.format("doUpdateMenuAction.actionMap:%s", actionMap));
    }
}
